package controllers

import (
	"encoding/json"
	"fmt"
	"ginstudydemo.com/main/dao"
	"ginstudydemo.com/main/models"
	"ginstudydemo.com/main/service"
	"github.com/gin-gonic/gin"
	"gorm.io/datatypes"
	"math/rand"
	"net/http"
	"time"
)

type ITopicController interface {
	CreateTestDataHandler()
}

type TopicController struct{}

func NewTopicController() *TopicController {
	return &TopicController{}
}

// GetUsePageHandler 分页获取指定分类资源数据
func (u TopicController) GetUsePageHandler(c *gin.Context) {

	var query models.TopicPageParams
	var pagination models.PaginationParams
	// 获取查询参数（除分页参数）
	if err := c.ShouldBindQuery(&query); err != nil {
		service.ReturnErr(c, "9999", err.Error())
		c.Abort() // 终止后续处理
		return    // 确保不会继续执行后续代码
	}

	// 获取分页参数
	if qErr := c.ShouldBindQuery(&pagination); qErr != nil {
		service.ReturnErr(c, "9999", qErr.Error())
		c.Abort() // 终止后续处理
		return    // 确保不会继续执行后续代码
	}

	data, count, pageNum, pageSize, modelErr := models.NewTopicModel().GetUsePage(query, pagination)

	if !(modelErr == nil) {
		service.ReturnErr(c, "9999", modelErr.Error())
		c.Abort()
		return
	}
	// 是否还有下一页
	hasNextPage := int64(pageNum)*int64(pageSize) < count

	service.ReturnSuccess[models.TopicResList](c, "2000", "ok", models.TopicResList{
		Total:       count,
		PageSize:    pageSize,
		PageNum:     pageNum,
		List:        data,
		HasNextPage: hasNextPage,
	})

}

// AddTopicTestData 增加专题测试数据
func (u TopicController) AddTopicTestData(c *gin.Context) {
	// 1. 初始化随机数生成器
	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	// 2. 开启事务 - 注意这里不要指定表名
	tx := dao.Db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 3. 生成并插入测试数据
	count := 30
	coverURL := "https://sanjitian-1256310189.cos.ap-chengdu.myqcloud.com/gin_test/2025/02/2025_02_19_15_36_08_2712_2.jpg"

	for i := 0; i < count; i++ {
		selectedTags := []string{"中药", "学位", "病症"} // 示例数据

		// 序列化为 JSON
		tagsJSON, err := json.Marshal(selectedTags)
		if err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{"error": "标签序列化失败"})
			return
		}

		now := time.Now()
		endTime := now.AddDate(0, 1, 0)

		topic := models.Topic{
			Title:            fmt.Sprintf("测试专题 %d", i+1),
			CoverImage:       coverURL,
			CardCoverImage:   coverURL,
			BannerCoverImage: coverURL,
			Introduction:     "这是一个自动生成的测试专题",
			WebURL:           "http://www.cntcm.com.cn/news.html?aid=190565",
			CategoryID:       int64(r.Intn(10) + 1),
			Tags:             datatypes.JSON(tagsJSON), // 使用 datatypes.JSON,
			ContentType:      int8(1),
			Location:         int8(r.Intn(2) + 1),
			SortOrder:        int16(r.Intn(100)),
			Status:           1,
			ResourceCount:    uint(r.Intn(100)),
			ViewCount:        uint(r.Intn(1000)),
			LikeCount:        uint(r.Intn(500)),
			CollectCount:     uint(r.Intn(300)),
			CreateBy:         1,
			UpdateBy:         1,
			IsDeleted:        0,
			StartTime:        now,
			EndTime:          endTime,
			ReleaseDate:      now, // 关键修正点
			CreateTime:       now,
			UpdateTime:       now,
		}

		if err := tx.Table("topic").Create(&topic).Error; err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{
				"error":   fmt.Sprintf("插入失败: %v", err),
				"details": "请检查tags字段的JSON序列化是否正确",
			})
			return
		}
	}

	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "提交事务失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": fmt.Sprintf("成功生成%d条专题测试数据", count),
	})
}

type Topic struct {
	ID int64 `gorm:"primaryKey"`
}

// AddResTestDataToTopic 往专题添加测试资源数据
func (u TopicController) AddResTestDataToTopic(c *gin.Context) {
	// 1. 查询所有专题ID
	var topicIDs []int64
	if err := dao.Db.Table("topic").Model(&models.Topic{}).Pluck("id", &topicIDs).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("查询专题ID失败: %v", err)})
		return
	}

	if len(topicIDs) == 0 {
		c.JSON(http.StatusOK, gin.H{"message": "没有找到专题数据"})
		return
	}

	// 2. 查询所有存在的资源ID
	var existingResourceIDs []int64
	if err := dao.Db.Table("resource").Model(&models.Resource{}).Pluck("id", &existingResourceIDs).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("查询资源ID失败: %v", err)})
		return
	}

	if len(existingResourceIDs) == 0 {
		c.JSON(http.StatusOK, gin.H{"message": "没有找到资源数据"})
		return
	}

	// 3. 创建随机数生成器
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	totalInserted := 0
	minResources := 20 // 最少20条
	maxResources := 50 // 最多50条

	// 4. 开启事务
	tx := dao.Db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	for _, topicID := range topicIDs {
		// 随机决定要插入的资源数量 (20-50)
		resourceCount := r.Intn(maxResources-minResources+1) + minResources

		// 确保不超过可用资源数
		if resourceCount > len(existingResourceIDs) {
			resourceCount = len(existingResourceIDs)
		}

		// 从现有资源ID中随机选择
		resourceIDs := selectRandomResources(r, existingResourceIDs, resourceCount)

		// 准备批量插入数据
		var records []models.TopicResource
		for _, resourceID := range resourceIDs {
			records = append(records, models.TopicResource{
				TopicID:    topicID,
				ResourceID: resourceID,
				CreateBy:   1,
				CreateTime: time.Now(),
			})
		}

		// 批量插入
		if err := tx.Table("topic_resource").CreateInBatches(records, 100).Error; err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": fmt.Sprintf("专题ID %d 插入失败: %v", topicID, err),
			})
			return
		}

		totalInserted += len(records)
		fmt.Printf("专题ID %d 成功关联 %d 个资源\n", topicID, len(records))
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "提交事务失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": fmt.Sprintf("全部完成! 共为 %d 个专题关联了 %d 条资源", len(topicIDs), totalInserted),
	})
}

// 从现有资源中随机选择
func selectRandomResources(r *rand.Rand, existingIDs []int64, count int) []int64 {
	// 复制切片避免修改原数据
	ids := make([]int64, len(existingIDs))
	copy(ids, existingIDs)

	// 洗牌算法
	r.Shuffle(len(ids), func(i, j int) {
		ids[i], ids[j] = ids[j], ids[i]
	})

	// 返回前count个
	return ids[:count]
}
